﻿using CommunityToolkit.Mvvm.Input;
using System.Diagnostics;
using System.IO;
using System.Windows.Input;
using VideoTools.Tasks;
using VideoTools.Util;
using TaskStatus = VideoTools.vo.TaskStatus;

namespace VideoTools.Commands
{
    public class BatchFFmpegCommands : NotifyPropertyBase
    {
        private static volatile BatchFFmpegCommands _instance;
        private static readonly object SyncRoot = new object();
        static Dictionary<string, BatchFFmpegTaskItem> Task_Context =
            new Dictionary<string, BatchFFmpegTaskItem>();
        static Dictionary<string, IProgress<double>> Progress_Context =
            new Dictionary<string, IProgress<double>>();
        public static BatchFFmpegCommands Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (SyncRoot)
                    {
                        if (_instance == null)
                        {
                            _instance = new BatchFFmpegCommands();
                        }
                    }
                }

                return _instance;
            }
        }

        private BatchFFmpegCommands()
        {
        }
        private string _batchFile;

        public string BatchFile
        {
            get => _batchFile;
            set => SetProperty(ref _batchFile, value);
        }
        private string _batchInfo;

        public string BatchInfo
        {
            get => _batchInfo;
            set => SetProperty(ref _batchInfo, value);
        }
        private ICommand _openBatchDialogCommand;
        public ICommand OpenBatchDialogCommand =>
                    _openBatchDialogCommand
                    ?? (
                        _openBatchDialogCommand = new RelayCommand<object>(o =>
                        {
                            OpenFileDialog openFileDialog = new OpenFileDialog();
                            string filter = "ffmpeg批文件(*.txt)|*.txt";

                            openFileDialog.Filter = filter;
                            openFileDialog.RestoreDirectory = true;
                            openFileDialog.FilterIndex = 1;
                            if (openFileDialog.ShowDialog() == DialogResult.OK)
                            {
                                string filePath = openFileDialog.FileName;
                                FileInfo fileInfo = new FileInfo(filePath);
                                string name = fileInfo.Name;
                                BatchFile = filePath;
                                name = name.Split(".")[0];
                                string[] lines = File.ReadAllLines(BatchFile);
                                if (lines == null || lines.Length == 0)
                                {
                                    BatchInfo = "文件中不存在ffmpeg命令";
                                    return;
                                }
                                int count = 0;
                                int failCount = 0;
                                for (int i = 0; i < lines.Length; i++)
                                {
                                    string line = lines[i];
                                    if (line == null || line.Trim().Length == 0)
                                    {
                                        continue;
                                    }
                                    if (line.ToLower().Contains("ffmpeg"))
                                    {
                                        count++;
                                    }
                                    else
                                    {
                                        failCount++;
                                    }
                                    int cnt = BatchFFmpegTaskQueueManager.Instance.Tasks.Count;
                                    BatchFFmpegTaskQueueManager.Instance.AddTask(
                                        line,
                                        TaskAction
                                    );
                                }
                                doneCount = BatchFFmpegTaskQueueManager
                                          .Instance.Tasks.Where(t => t.Status == TaskStatus.Completed)
                                          .Count();
                                taskCount = BatchFFmpegTaskQueueManager.Instance.Tasks.Count;
                                TaskCount = "总任务 " + taskCount;
                                DoneCount = "已完成 " + doneCount;
                                BatchInfo = "共 " + count + " 条ffmpeg命令，" + failCount + " 条无效命令";
                            }
                            else
                            {
                                BatchInfo = "";
                                return;
                            }
                        })
                    );

        private string _DoneCount = "已完成 0";

        public string DoneCount
        {
            get => _DoneCount;
            set => SetProperty(ref _DoneCount, value);
        }


        private string _TaskCount = "总任务 0";

        public string TaskCount
        {
            get => _TaskCount;
            set => SetProperty(ref _TaskCount, value);
        }

        private int taskCount;
        private int doneCount;
        private ICommand _DoCommand;
        private ICommand _CopyTaskLogCommand;

        public ICommand CopyTaskLogCommand =>
            _CopyTaskLogCommand
            ?? (
                _CopyTaskLogCommand = new RelayCommand<object>(o =>
                {
                    if (o == null)
                        return;
                    BatchFFmpegTaskItem model = (BatchFFmpegTaskItem)o;
                    Utils.CopyToClipboard(model.CopyLog(), "日志");

                })
            );
        public ICommand DoCommand =>
            _DoCommand
            ?? (
                _DoCommand = new RelayCommand<object>(o =>
                {
                    if (BatchFFmpegTaskQueueManager.Instance.Tasks.Where(t => t.Status != TaskStatus.Completed).Count() == 0)
                    {
                        return;
                    }
                    BatchFFmpegTaskQueueManager.Instance.StartProcessing();
                })
            );

        private Action<CancellationToken, IProgress<double>, BatchFFmpegTaskItem> TaskAction = (
            token,
            progress,
            item
        ) =>
        {
            try
            {
                Process process = new Process();
                token.Register(() =>
                {
                    if (!process.HasExited)
                    {
                        item.Killed = true;
                        process.Kill();
                    }
                });
                process.StartInfo.FileName = "ffmpeg ";
                process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
                string param = getParam(item);
                item.Info(AppConstants.DoubleClickMessage);
                item.Info("参数 ffmpeg " + param);
                process.StartInfo.Arguments = param;
                process.StartInfo.CreateNoWindow = true; //显示命令行窗口
                process.StartInfo.UseShellExecute = false;
                IDictionary<string, string?> environment = process.StartInfo.Environment;
                environment["taskItem_cmd"] = item.Cmd;
                Task_Context.Add(item.Cmd, item);
                Progress_Context.Add(item.Cmd, progress);
                //将输出信息重定向
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.EnableRaisingEvents = true;
                process.Exited += new EventHandler(scale_Exited);
                process.OutputDataReceived += new DataReceivedEventHandler(
                    scale_OutputDataReceived
                );
                process.ErrorDataReceived += new DataReceivedEventHandler(scale_ErrorDataReceived);
                process.Start();
                //开始异步读取输出
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                process.WaitForExit();
            }
            catch (Exception e)
            {
                item.Status = TaskStatus.Failed;
            }
            finally { }
        };

        static void scale_OutputDataReceived(Object sender, DataReceivedEventArgs e) { }

        static void scale_ErrorDataReceived(Object sender, DataReceivedEventArgs e)
        {
            Process process = (Process)sender;
            string cmd = process.StartInfo.Environment["taskItem_cmd"];
            BatchFFmpegTaskItem taskItem = Task_Context[cmd];
            IProgress<double> progress = Progress_Context[cmd];
            string info = e.Data;
            if (info == null)
            {
                return;
            }
            taskItem.Info(e.Data);
        }

        static void scale_Exited(Object sender, EventArgs e)
        {
            Process process = (Process)sender;
            string cmd = process.StartInfo.Environment["taskItem_cmd"];
            BatchFFmpegTaskItem taskItem = Task_Context[cmd];
            taskItem.Info("任务退出" + cmd);
            Task_Context.Remove(cmd);
            Progress_Context.Remove(cmd);
        }

        private static string getParam(BatchFFmpegTaskItem item)
        {
            //cpu和gpu命令已在上层处理好了
            string param = item.Cmd;
            param = param.Replace("ffmpeg ", "");            
            return param;
        }
    }
}
